#include <CSLP/CSLP.h>
#include <stdio.h>
#include <string.h>

#define PORT 45682
#define SIZE_OF_BUFFER 25600

struct thread_data_t {
  int is_server_listening;
  CSLP_MUTEX mutex_stdout;
};

void client(void *arg)
{
  int byte_received;
  unsigned long server_ip;
  unsigned short server_port;
  char buffer [SIZE_OF_BUFFER];
  struct thread_data_t *data;
  CSLP_TCPSOCKET client_tcp;
  CSLP_UDPSOCKET client_udp;

  data = (struct thread_data_t*)(arg);
  client_udp = CSLP_InitUDPSocket();
  client_tcp = CSLP_InitTCPSocket();
  ////////////////////////////////////////////////
  ///TEST TCP
  ////////////////////////////////////////////////
  //attente de la mis en place du serveur
  while (data->is_server_listening == 0)
    {
      CSLP_Sleep(30);
    }
  //connexion au serveur
  if (CSLP_Connect(client_tcp,
		   CSLP_StringIPToULong("127.0.0.1"),
		   PORT) != NONE)
    {
      perror("La connexion au serveur a échouée ");
      return;
    }
  //envois de données
  strcpy(buffer, "Ici le client");
  if (CSLP_SendString(client_tcp, buffer) != NONE)
    {
      perror("Impossible d'envoyer des données au serveur ");
      return;
    }
  //réception de données
  if (CSLP_Receive(client_tcp, buffer, SIZE_OF_BUFFER, &byte_received) != NONE)
    {
      perror("La réception de données a échouée ");
      return;
    }
  else
    {
      CSLP_WaitToLockMutex(&(data->mutex_stdout));
      printf("Chaine reçus du serveur : %s\n", buffer);
      CSLP_UnlockMutex(&(data->mutex_stdout));
    }
  CSLP_CloseTCPSocket(client_tcp);
  ////////////////////////////////////////////////
  /// TEST UDP
  ////////////////////////////////////////////////
  //attente de la mis en place du serveur
  while (data->is_server_listening == 0)
    {
      CSLP_Sleep(30);
    }
  //envois de données
  strcpy(buffer, "Ici le client");
  if (CSLP_SendTo(client_udp,
		  buffer,
		  strlen(buffer) + 1,
		  CSLP_StringIPToULong("127.0.0.1"),
		  PORT) != NONE)
    {
      perror("L'envois de données a échoué ");
      return;
    }
  //réception de données
  if (CSLP_ReceiveFrom(client_udp,
		       buffer,
		       SIZE_OF_BUFFER,
		       &byte_received,
		       &server_ip,
		       &server_port) != NONE)
    {
      perror("La réception de données a échouée ");
      return;
    }
  else
    {
      CSLP_WaitToLockMutex(&(data->mutex_stdout));
      printf("Chaine reçus du serveur : %s\n", buffer);
      CSLP_UnlockMutex(&(data->mutex_stdout));
    }
  //fermeture
  CSLP_CloseUDPSocket(client_udp);
  return;
}

int main(int argc, char **argv)
{
  int byte_received;
  char buffer[SIZE_OF_BUFFER];
  unsigned long client_ip;
  unsigned short client_port;
  CSLP_THREAD thread_client;
  CSLP_TCPSOCKET server_tcp, client_tcp;
  CSLP_UDPSOCKET server_udp;
  struct thread_data_t thread_data;

  thread_data.is_server_listening = 0;
  CSLP_InitMutex(&(thread_data.mutex_stdout));
  server_tcp = CSLP_InitTCPSocket();
  server_udp = CSLP_InitUDPSocket();
  CSLP_CreateThread(&thread_client, client, &thread_data);
  ////////////////////////////////////////////////
  /// TEST DES SOCKETS TCP
  ////////////////////////////////////////////////
  printf("\nTEST DES SOCKETS TCP:\n");
  //ouverture du serveur
  if (CSLP_Listen(server_tcp, PORT) != 0)
    {
      perror("Impossible d'écouter le port ");
      return -1;
    }
  //attente de connexion
  thread_data.is_server_listening = 1;
  if (CSLP_Accept(server_tcp, &client_tcp, NULL, NULL) != 0)
    {
      perror("La connexion du client a échouée ");
      return -1;
    }
  thread_data.is_server_listening = 0;
  //réception d'une chaine de caractère
  if (CSLP_Receive(client_tcp, buffer, SIZE_OF_BUFFER, &byte_received) != NONE)
    {
      perror("La réception a échouée ");
      return -1;
    }
  else
    {
      CSLP_WaitToLockMutex(&(thread_data.mutex_stdout));
      printf("Le serveur a reçus la chaine : %s\n", buffer);
      CSLP_UnlockMutex(&(thread_data.mutex_stdout));
    }
  //envois de données
  memset(buffer, '\0', SIZE_OF_BUFFER);
  memset(buffer, 'a', SIZE_OF_BUFFER);
  memset(buffer, '%', 16436);
  if (CSLP_SendString(client_tcp, buffer) != NONE)
    {
      perror("L'envois de données a échoué ");
      return -1;
    }
  //fermeture des sockets
  CSLP_CloseTCPSocket(client_tcp);
  CSLP_CloseTCPSocket(server_tcp);
  ////////////////////////////////////////////////
  /// TEST DES SOCKETS UDP
  ////////////////////////////////////////////////
  printf("\nTEST DES SOCKETS UDP:\n");
  //liage du socket à un port
  if (CSLP_Bind(server_udp, PORT) != 0)
    {
      perror("Le liage du socket a échoué ");
      return -1;
    }
  thread_data.is_server_listening = 1;
  //Réception de données
  if (CSLP_ReceiveFrom(server_udp, 
		       buffer, 
		       SIZE_OF_BUFFER, 
		       &byte_received, 
		       &client_ip, 
		       &client_port) != NONE)
    {
      perror("La réception de données a échouée ");
      return -1;
    }
  else
    {
      thread_data.is_server_listening = 0;
      CSLP_WaitToLockMutex(&(thread_data.mutex_stdout));
      printf("Le serveur a reçus la chaine : %s\n", buffer);
      CSLP_UnlockMutex(&(thread_data.mutex_stdout));
    }
  //Envois de données
  strcpy(buffer, "Ici le serveur");
  if (CSLP_SendTo(server_udp,
		  buffer,
		  strlen(buffer) + 1,
		  client_ip,
		  client_port) != NONE)
    {
      perror("L'envois de données a échouée ");
      return -1;
    }
  //fermeture
  printf("Fin des tests\n");
  CSLP_CloseUDPSocket(server_udp);
  CSLP_WaitThread(thread_client);
  CSLP_DeleteMutex(&(thread_data.mutex_stdout));
  return 0;
}
